@args String header
@extends(_base, header: header)
@returnIf(!isDev())

@render()

@ifNot(_error instanceof act.util.ActError) {
@section(head){
@render(moreStyles)
}
@return
}
@{
act.util.ActError actError = (act.util.ActError)_error;
act.app.SourceInfo sourceInfo = actError.sourceInfo();
act.app.SourceInfo templateSourceInfo = null;
if (_error instanceof act.view.TemplateException) {
templateSourceInfo = ((act.view.TemplateException) actError).templateSourceInfo();
}
act.route.RouteInfo routeInfo = null != _action ? act.route.RouteInfo.of(_action) : null;
boolean isCompileError = actError.getCauseOrThis() instanceof act.app.CompilationException;
List<String> stackTrace;
if (isCompileError || null != templateSourceInfo) {stackTrace = null;}
else {stackTrace = actError.stackTrace();}
  boolean activeSource = null == templateSourceInfo && null != sourceInfo;
  boolean activeStack = !activeSource && (null != stackTrace && !stackTrace.isEmpty());
  }


  @section(head){
  <style>
    .detail {
      font-family: "Envy Code R", "Fira Code", "Source Code Pro Semibold",  Monaco, Courier, monospace;
      font-size: 11pt;
      padding: 20px;
      padding-top: 8px;
      border: 1px solid #888;
      display: none;
      overflow: auto;
    }
    .detail.active {
      display: block;
    }
    .error-message {
      padding: 8px;
      border: 1px solid #888;
      font-size: 11pt;
      margin-bottom: 20px;
      color: #f54400;
    }
    .source-info .hljs {
      padding: 0;
    }
    .source-info .line.error, .trace-line.error {
      background-color: #e00;
      color: #fff;
      cursor: pointer;
    }
    .source-info .line span {
      display: inline-block;
    }
    .source-info .line span.line-number {
      min-width: 20px;
      text-align: right;
      color: #eee;
    }
    .source-info .line.big-line, .trace-line.big-line {
      padding-top: 0.5em;
      font-weight: bold;
    }
    .source-info.active {
      background-color: #000;
      color: #aaa;
    }
    #stacktrace .exception {
      font-size: 9pt;
      font-weight: bold;
      padding-bottom: 5px;;
    }
    #stacktrace.active {
      background-color: #000;
      color: #aaa;
    }
    .trace-line {
      padding: 4px 5px;
    }
    .template-line, .source-line {
      padding: 2px 0px;
    }
    .tabs .tab {
      display: inline-block;
      padding: 2px 10px;
      cursor: pointer;
      font-size: 9pt;
      font-weight: bold;
    }
    .tabs .tab.active {
      background: #efefef;
      color: #333;
    }
  </style>
  @render(moreStyles)
  <link rel="stylesheet" href="/asset/act/css/highlight.min.css">
  <script src="/asset/act/js/jquery-1.11.3.min.js"></script>
  <script src="/asset/act/js/highlight.min.js"></script>
  <script src="/asset/act/js/highlight.java.min.js"></script>
  }

  @def Throwable getCauseOrThis(Throwable t) {
    Throwable cause = t.getCause();
    return null == cause ? t : cause;
  }

  <pre class="error-message">
  @if(templateSourceInfo) {
  @(((act.view.TemplateException) actError).errorMessage().raw())
  } else {
    @actError.getCauseOrThis().getClass().getName(): <b>@actError.getCauseOrThis().getLocalizedMessage()</b>
  }
  </pre>

  <div class="tabs">
    @if(templateSourceInfo) {
    <div id="tab-template" class="code tab active" onclick="showTemplate()">@actMsg("error_page.template_code")</div>
    }
    @if(sourceInfo) {
    <div id="tab-source" class="code tab @if(activeSource){active}" onclick="showSource()">@actMsg("error_page.source_code")</div>
    }
    @if(stackTrace) {
    <div id="tab-stacktrace" class="stacktrace tab @if(activeStack){active}"" onclick="showStacktrace()">@actMsg("error_page.stacktrace")</div>
    }
  </div>

  @if(templateSourceInfo) {
  <div id="template" class="detail source-info active">
    @for(String line: templateSourceInfo.lines()) {
    @{
    String cls = line_index == templateSourceInfo.lineNumber() ? "error nohighlight" : ""
    }
    <div class="template-line line @cls" data-line="@line_index">
      <span class="line-number">@line_index</span>
      <span class="line-code">@line.sp2nbsp()</span>
    </div>
    }
  </div>
  }
  @if(stackTrace) {
  <div id="stacktrace" class="detail @if(activeStack) {active}">
    @{boolean traceErrorSet = false;}
    @for(int i = 0; i < stackTrace.size(); ++i) {
      @{
        String trace = stackTrace.get(i);
        String nextTrace = "";
        if (i < stackTrace.size() - 1) {
          nextTrace = stackTrace.get(i + 1);
        }
        String cls = "";
        if (!traceErrorSet) {
          if (null != sourceInfo && trace.contains(sourceInfo.fileName() + ":" + sourceInfo.lineNumber())) {
            cls = "error";
            traceErrorSet = true;
          } else if (actError.isErrorSpot(trace, nextTrace)) {
            cls = "error";
            traceErrorSet = true;
          }
        }
        if (trace.contains("Caused by")) {
          cls = cls + " big-line";
        }
      }
      <div class="trace-line line @cls">@trace</div>
    }
  </div>
  }

  @returnIf(null == sourceInfo && null == templateSourceInfo)

  @if(sourceInfo) {
  <div id="source" class="detail source-info @if(activeSource){active}">
    @for(String line: sourceInfo.lines()) {
    @{
    String cls = line_index == sourceInfo.lineNumber() ? "error nohighlight" : ""
    }
    <div class="source-line line @cls" data-line="@line_index">
      <span class="line-number">@line_index</span>
      <span class="line-code">@line.sp2nbsp()</span>
    </div>
    }
  </div>
  }


  <script>
    function showSource() {
      @if (templateSourceInfo) {
        document.getElementById("template").className = "detail source-info";
        document.getElementById("tab-template").className = "tab";
      }

      @if (stackTrace) {
        document.getElementById("stacktrace").className = "detail";
        document.getElementById("tab-stacktrace").className = "tab";
      }

      @if (sourceInfo) {
        document.getElementById("source").className = "detail source-info active";
        document.getElementById("tab-source").className = "tab active";
        var e = new Event('show-source');
        window.dispatchEvent(e);
      }
    }
    function showTemplate() {
      @if(templateSourceInfo) {
        document.getElementById("template").className = "detail source-info active";
        document.getElementById("tab-template").className = "tab active";
      }
      @if (stackTrace) {
        document.getElementById("stacktrace").className = "detail";
        document.getElementById("tab-stacktrace").className = "tab";
      }

      @if (sourceInfo) {
        document.getElementById("source").className = "detail source-info";
        document.getElementById("tab-source").className = "tab";
      }
      var e = new Event('show-template-source');
      window.dispatchEvent(e);
    }
    function showStacktrace() {
      @if(templateSourceInfo) {
        document.getElementById("template").className = "detail source-info";
        document.getElementById("tab-template").className = "tab";
      }

      @if (stackTrace) {
        document.getElementById("stacktrace").className = "detail active";
        document.getElementById("tab-stacktrace").className = "tab active";
      }

      @if (sourceInfo) {
        document.getElementById("source").className = "detail source-info";
        document.getElementById("tab-source").className = "tab";
      }
    }
    @if (templateSourceInfo) {
      function scrollTemplateSource() {
        var element = document.getElementsByClassName('template-line line error nohighlight')[0];
        element.scrollIntoView();
        element.parentElement.scrollTop -= 100;
      }
      var templateSourceLoaded = false;
      $('body').on('click', '#template .line.error', function() {
        $.getJSON('http://localhost:8091?message=@(templateSourceInfo.fileName()):@(templateSourceInfo.lineNumber())')
      });
      var windowHeight = $(window).height(), maxDetailHeight = windowHeight - 280;
      $('.detail').css({maxHeight: maxDetailHeight + 'px'});
      window.addEventListener('show-template-source', function() {
        if (templateSourceLoaded) return;
        templateSourceLoaded = true;
        scrollTemplateSource();
      }, false);
      $(document).ready(function() {
        $('.line-code').each(function(i, block) {
          hljs.highlightBlock(block);
        });
      });
      setTimeout(scrollTemplateSource, 200);
    }
    @if (sourceInfo) {
      function scrollJavaSource() {
        if (sourceLoaded) return;
        sourceLoaded = true;
        var element = document.getElementsByClassName('source-line line error nohighlight')[0];
        element.scrollIntoView();
        element.parentElement.scrollTop -= 100;
      }
      var sourceLoaded = false;
      @{
        int linkedSourceLineNumber = sourceInfo.lineNumber();
        if (null != templateSourceInfo && templateSourceInfo.fileName().equals(sourceInfo.fileName())) {
          linkedSourceLineNumber = templateSourceInfo.lineNumber();
        }
      }
      $('body').on('click', '#source .line.error', function() {
        $.getJSON('http://localhost:8091?message=@(sourceInfo.fileName()):@linkedSourceLineNumber')
      });
      var windowHeight = $(window).height(), maxDetailHeight = windowHeight - 280;
      $('.detail').css({maxHeight: maxDetailHeight + 'px'});
      window.addEventListener('show-source', scrollJavaSource, false);
      $(document).ready(function() {
        $('.line-code').each(function(i, block) {
          hljs.highlightBlock(block);
        });
      });
      @if(activeSource) {
        setTimeout(scrollJavaSource, 200);
      }
    }
  </script>